#pragma once

/*
*  用户使用muduo编写服务器程序
*/
#include "EventLoop.h"
#include "Acceptor.h"
#include "InetAddress.h"
#include "Noncopyable.h"
#include "EventLoopThreadPoll.h"
#include "Callbacks.h"

#include <functional>
#include <string>
#include <memory>
#include <atomic>
#include <unordered_map>

// 对外的服务器编程使用的类
class TcpServer : noncopyable
{
public:
    using ThreadInitCallback = std::function<void(EventLoop*)>;

    // 预制两个选项，表示是否对端口可重用
    enum Option
    {
        kNoReusePort,
        kReusePort
    };

    TcpServer(EventLoop* loop,
    const InetAddress& listenAddr,
    const std::string nameArg,
    Option option = kNoReusePort);
    ~TcpServer();

    void setThreadInitcallback(const ThreadInitCallback& cb) { threadInitCallback_ = cb; }
    void setConnectionCallback(const ConnectionCallback& cb) { connectionCallback_ = cb; }
    void setMessageCallback(const MessageCallback& cb) { messageCallback_ = cb; }
    void setWriteCompleteCallback(const WriteCompleteCallback& cb) { writeCompleteCallback_ = cb; }
    void setHighWaterMarkCallback(const HighWaterMarkCallback& cb,size_t highWaterMark) 
    { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark;  }
    // 设置底层subloop的个数
    void setThreadNum(int numThread);

    // 开启服务器监听
    void start();
private:
    void newConnection(int sockfd,const InetAddress& peerAddr);
    void removeConnection(const TcpConnectionPtr& conn);
    void removeConnectionInLoop(const TcpConnectionPtr& conn);

    using ConnectionMap = std::unordered_map<std::string,TcpConnectionPtr>;
private:
    EventLoop* loop_; // baseLoop 用户定义的loop

    const std::string ipPort_;
    const std::string name_;

    std::unique_ptr<Acceptor> acceptor_; // 运行在mainLoop，任务就是监听新连接事件

    std::shared_ptr<EventLoopThreadPoll> threadPool_; // one loop per thread

    ConnectionCallback connectionCallback_; // 有新连接事件的回调
    MessageCallback messageCallback_; // 有读写消息的回调
    WriteCompleteCallback writeCompleteCallback_;  // 消息发送完成以后的回调
    HighWaterMarkCallback highWaterMarkCallback_; // 防止server端发送数据太快，subloop处理太慢，导致数据丢失
    ThreadInitCallback threadInitCallback_; // loop线程初始化的回调
    std::atomic_int started_;
    size_t highWaterMark_;

    int nextConnId_;
    ConnectionMap connections_; // 保存所有的连接
};